There is no spoon

Legacy:Simulated Function

From Unreal Wiki, The Unreal Engine Documentation Site
Jump to: navigation, search

Roughly speaking, a simulated function is a function in an Actor-derived class that can be called on a client in a network game.

Conversely, non-simulated functions in an Actor-derived class cannot be executed on a client in a network game, except in some special cases where the client owning that actor is the authority on that actor.

Simulated functions are declared with the function modifier keyword simulated:

simulated function bool MyFunction(bool FirstParam)
{
 // function code
}


Strict Definition[edit]

Functions that are called in the context of an actor will not be executed if the Actor's local Role (not RemoteRole!) is less than or equal to ROLE_SimulatedProxy unless the function is declared as simulated or as native.

Some Clarifications[edit]

  • An Actor's clientside Role takes the value of the serverside RemoteRole and the clientside RemoteRole takes the serverside value of Role. This definition talks about the local Role value.
  • "Less than or equal to ROLE_SimulatedProxy" actually means ROLE_SimulatedProxy or ROLE_DumbProxy. ROLE_None would also be "less than" ROLE_SimulatedProxy, but this value prevents actors from being replicated, so it should never appear as the value of the actor's local Role.
  • Functions in object classes not derived from Actor are not affected by network roles and thus will always execute.
  • Static functions are executed in the context of a class (as opposed to the context of an actor or other object), which means they are not affected by network roles and thus will always execute.
  • It doesn't matter where the function call originated. The definition described above is always applied if the function is supposed to be executed in the context of an actor.

Executing Simulated Functions[edit]

Being able to execute a function doesn't mean it will be executed. Function calls always stay on the same machine unless there's a valid replication statement for the function. In that case the function will only be executed on the machine the function call was replicated to.

This means that you basically have two ways of executing a simulated function client-side:

  1. Call it from another client-side function. PostBeginPlay, Tick or HitWall are good candidates for this. Beware of simulated Timer functions, they will only be executed if SetTimer was actually executed on that machine, i.e. if you set the timer on the server, then Timer will only be called on the server, even if it is declared simulated. Server and client have independent timers.
  2. Replicate the function call from the server to the client. Note that replicated functions can only be replicated to a single machine, either from the client of the player owning this actor to the server or from the server to the client of the player owning this actor. Replicated functions will be executed only on the replication destination.

Simulated Engine Events[edit]

Events like Tick, (Pre/Post/PostNet)BeginPlay, Destroyed, Timer, Begin/EndState and others are always called on the server and the clients by the engine, but like other functions they will only be executed if they are declared as simulated.

There is no synchronization between events on the server and the clients! For example the number of Tick() calls on a client can greatly differ from the number of calls on the server. As mentioned above already, server and client have independent timers and the same goes for states.

Replication Myth: "Simulated Functions Can Only Be Called From Other Simulated Functions"[edit]

This statement is an over-simplification and not true at all. Simulated functions can actually be called from whichever function you like, the only condition is that they actually do get called.

Think of function calls as messages consisting of:

  1. a function specification,
  2. an object to call the function on and
  3. parameter values.

You can send as many of these messages around as you like, but the engine will ignore them if certain conditions are not met, this includes the constraint that the function needs to be simulated or native when the function is called on non-authorative client instances of an actor.

So in order to call a simulated function all you need is an object (actually an actor) containing the function. The engine really doesn't care where the function call originated. For example the GUI is implemented using classes not derived from Actor, so the functions in these classes don't need to be simulated, yet there's no problem calling simulated functions from them.

PlaySound() and PlayOwnedSound() Replication Magic[edit]

Most functions do not care how they have been called. A noteable exception are the native Actor.PlaySound() and Actor.PlayOwnedSound() functions, which alter their behavior on the server based on whether they have been called from a simulated function.

PlaySound() 
This function plays the sound locally if it was called on a client or from a simulated function. If called from a non-simulated function on the server, it will broadcast the sound to all clients.
PlayOwnedSound() 
This function plays the sound locally if it was called on a client. If called on the server, the sound will be broadcasted to all clients with one exception: If the sound player is a Pawn (or is owned by a Pawn) and that Pawn is not controlled locally, then the client owning this Pawn will not receive the sound.

Overriding Simulated Functions[edit]

The simulated keyword is not inherited when you override a (non)simulated function in a state or subclass. If the overridden function is not simulated and your new function is, you will not be able to execute Super.YourFunction() on clients, simply because that is a completely different function which may not be executed on simulated proxies.

If you override a simulated function and don't declare the new function as simulated as well, your new function can not be executed on simulated proxies. This also means you have no chance to call Super.YourFunction(), so be careful with this. A good way around this is:

simulated function OverriddenFunction()
{
  if ( Role == ROLE_Authority ) {
    // put your new code here, it will only run on the server
  }
  Super.OverriddenFunction();  // execute the super version on server and clients
}

Simulated States[edit]

States can be declared simulated as well, but you will rarely need it as it only applies to the state code outside any function.

Clientside instances of actors can always switch to states, whether these are declared simulated or not. Functions in these states will override global (non-state) functions with the same name as usual. The same rules apply as with functions overridden in subclasses – neither the state's nor the overridden function's simulated flag is inherited. In other words:

  • You can have non-simulated function in simulated states and they will behave like non-simulated functions.
  • You can have simulated functions in non-simulated states and they will behave like simulated functions.

Switching states is not synchronized between server and clients! Like with timers and other engine events, states are changed independently.

Related Topics[edit]

Discussion[edit]

Foxpaw: I have a few questions about simulated functions:

  • If you declare an "entry point" as simulated, will it get called on all clients? For instance, say I declare Tick as simulated.. does every client tick on it's own based on it's own framerate, or does the server have to replicate the tick function?
  • If entry points are simulated automatically without being replicated, what will happen if I set up a replication statement for that function? Will it be run twice, or does the engine recognize the function in the replication statement and thus run it only once? If so, is it the replicated or local version that gets run?
  • Variables are replicated only if they have been changed.. if a variable is changed in a simulated function is it still considered changed or does the engine assume that the client changed it itself and thus it will still be in sync?
  • As I understand it, simulated functions can only call other simulated functions unless they are the authority version. If a simulated function (non-authority version) calls a non-simulated function, does the client simply ignore the call and proceed, or does it replicate the function to the server, wait for a response, then continue the function once the server has returned something?
  • If a superclass has a non-simulated function, and I override it and declare it as simulated, is it simulated or non-simulated? Or does the stuff I wrote in the override function simulate but not the Super.Function call? Or does the simulated call override the previous non-simulated call and force the simulated behaviour all the way up the class tree? What if a simulated function is overridden but the overridden version doesn't use the simulated keyword. (it is declared as non-simulated) Will the Super.Function still simulate instead of the overridden function?

Mr Evil: I have a few answers about simulated functions:

  • They are automatically simulated. They are called on the client automatically, not replicated, as a quick experiment will show the bandwidth usage does not change if you simulate Tick.
  • You can't set up a replication statement for them, since you can't replicate anything from a superclass, but have to have the replication statement in the class in which the function/variable is declared.
  • The engine knows nothing about what variables are being changed on the client in simulated functions, thus it goes ahead and replicates changed variables regardless of their client-side values.
  • Calls to non-simulated functions are simply ignored in this case.
  • You can simulate functions that are not simulated in a superclass if you wish, but calls to super.blah() will not be simulated (I think).

Kamek: I can say for sure that if the super version of a class has a function defined with the simulated keyword and you leave this keyword off of the overridden version of the subclass, NOTHING gets simulated. I had this problem the other day in Postal 2 when I was inserting extra code into PostBeginPlay of a subclass of PlayerController. One of the superclasses of my new controller (which in itself was a subclass of PlayerController) had defined PostBeginPlay as a simulated event, which initialized ragdoll skeletons. I left the "simulated" out of my new subclass and lo and behold, ragdolls stopped working in netplay. Putting the simulated keyword back in the function call made ragdolls work again. To make a long story short, overriding a function declared as a simulated function without the simulated keyword causes the ENTIRE function (and all of its Super.Blah() calls) to be non-simulated.

Lilguy: Ok, just to clarify:

  • functions are never "automatically simulated". There are certain events such as tick that are enabled on the client when they've been enabled on the server, but if you write a simulated function and call it on the server, it's not going to automatically be called on the client.
  • you MUST set up a replication statement for simulated functions if you ever want them to be called on a client. You can't replicate functions/vars things differently than a super class, but that's not to prevent you from declaring the function as simulated and calling it from your own function, or writing your own replicated simulated function from scratch.
  • non-simulated functions are never called on a client machine, unless they have RemoteRole = ROLE_AUTHORITY. If you call a non simulated function from a simulated function, it will return null if it's supposed to return an actor, will return false if it returns a bool, and I think will return 0 if it was a number.

EntropicLqd: Lilguy - Am I correct in thinking that for an Actor to have RemoteRole=ROLE_AUTHORITY on a client machine that Actor must have been spawned on that machine.

Foxpaw: Generally speaking, this will be the case. However, Unrealscript can set the Role and RemoteRole to whatever it wants - they are not declared as const variables. So technically, it doesn't have to have been spawned on that machine - but almost invariably will be.

Lilguy: Yeah, I think you can do it either way...If you want the client to have ROLE_AUTHORITY and spawn it on the server, then you need to set RemoteRole = ROLE_AUTHORITY (*I think*) because it swaps the roles when it replicates the actor. I'm looking at the HUD, however, which is clientside only, and they have RemoteRole = ROLE_NONE, which suggests to me that it is spawned on the client, RemoteRole = Role_None tells it that it doesn't belong on the server. And now that I think about it, setting Role = Role_none on the server and remoteRole = ROLE_AUTHORITY, it wouldn't even get replicated to the client initially...I think there is a different method for telling clients that they'll be the authority, but I can't remember what it is. I'll look into it...

EntropicLqd: Surely the meaning of RemoteRole is dependant upon where the Actor is spawned. So Actors spawned on the server with a RemoteRole = ROLE_None never get transmitted to the client machines. Conversely Actors spawned on a client with a RemoteRole = ROLE_None will never get spawned on the server. I would guess that the best way to spawn an Actor on the server that has authority on the client machine would be to add some code within either the Actor's PostNetReceive() event (if replicated variables were needed) or PostBeginPlay() event to set the Role and RemoteRole appropriately. I've got to admit it seems way easier (and maybe safer) to spawn the Actor on the machine where you want it to have authority.

Matariel: I think the best way would be to set the actor's bTearOff = true followed by one of these within the same tick

if (NetMode == NM_DedicatedServer) 
{
 Destroy();
}

Wormbo: The keyword simulated is only evaluated on the local machine, so the value of RemoteRole is irrelevant, you're slightly over-complicating the problem here. Everything you need to know about the Role variable in connection with the simulated keyword are described at the top of this page and on the page about Role and RemoteRole:

Simulated functions are allowed to be executed on any machine while non-simulated functions require ROLE_AutonomousProxy or higher.
The server's RemoteRole becomes the client's Role.

That's all – no "they can only be called from..." or "they can only call" stuff. They can be called from anywhere (as long as that calling function or state code is actually executed) and they can call anything. Note the difference between calling and executing functions again: whether the called function is actually executed after it has been called from code depends on whether it's simulated, replicated or whatever.
Same thing with function replication: You basically have to see it as a totally different and mostly unrelated concept. You have two machines and send function call requests (along with the function parameters) between them if certain conditions are met. Again, that's all. You will only get more difficulties with these already confusing topics if you start connecting them before you understand them individually. ;)
Replication is for communication between a server and its clients. The simulated keyword only tells, whether functions may be executed at all on a client. (also on a server or stand-alone game, but there Role==ROLE_Authority makes all functions pass the check)
Of course, these concepts have to be understood both in order to be able to write working netcode, but at least in theory you should separate them.

Lilguy: Yes, but suppose we have a non-simulated function which returns a bool. We call it on the clientside from some other function, and try to do something based on the value of what's returned from that function. True, we can "call" it, but since it's not executing, unreal script will return false, even though the function may have returned true if it were "executed." So I really don't think it's fair to say you can seperate the two, they're really closely tied together with respect to what codepath is actually executing.

Foxpaw: I suppose the simplest way to sum it up is:

A non-simulated function executes it's normal function body only on a Role of ROLE_AutonomousProxy or better if owned by the local player, or if it has ROLE_Authority regardless of owner. Otherwise it just executes a blank function.

A simulated function executes it's normal function body only on a Role of ROLE_SimulatedProxy or better. Otherwise it just executes a blank function.

The only difference is the Role required to get it to actually execute the code in the function, as opposed to skipping said code.

For the record, my personal preference is to make every function simulated, and just put my own Role, RemoteRole, and Level.NetMode checks in.

Wormbo: Lilguy, I said you have to understand them separately because technically they are independant concepts. Of course you usually need to apply them both and yes, in order to properly handle replicated functions you need to know about simulated functions. For a tutorial, however, it would also be possible to explain variable replication and simulated functions before ever mentioning function replication. For learning this stuff it's not really neccessary to talk about how to replicate functions before the reader learned why some functions need the simulated keyword and others don't.

Lilguy: The only reason I mentioned all of this was to correct some blatently untrue statements (in the discussion, not the document) that might confuse someone who was new to all this stuff. I don't know if I agree that simulated functions and role are independent concepts though. for instance, the statement "non simulated functions cannot be called on the client" is only true part of the time, and to understant that you NEED to understand what the role and remoterole are. I really don't see how any two concepts could be more closely tied together...

That said, I think this is an excellent document just the way it is; The passing mention of role at the beginning should be sufficient to make newcomers understand that they need to look at the role stuff eventually. Could you clarify this sentence though:

"Conversely, functions that aren't simulated can not be called on clients in a network game, but there are non-simulated functions which can be called from the client owning that actor"

What's the difference between "functions that aren't simulated" and "non-simulated functions" ? If they are the same, then it seems the sentence contradicts itself. May I suggest the following instead?

Conversely, non-simulated functions cannot be executed on a client in a network game, except in some special cases where the client owning that actor is the authority on that actor

That way it doesn't say "you can't do this, but, sometimes you can..."

Maybe I'm just reading it wrong, so take this all with a grain of salt of course...

Tarquin: Changed as suggested. But you can change stuff in documents yourself :)

Lilguy: My god Tarquin, do you ever sleep? :) thanks, I would have done it, but I didn't want to step on any toes here...

Tarquin: I live in the UK. It's breakfast time here :) One thing you could clear up is the "definition" heading. I've cleaned up the intro & added an example.

Wormbo: Who said simulation and role were independant? I only said simulated functions and replicated functions were two different things. Also simulated functions check the local Role, not the local RemoteRole.

Lilguy: Ok, one last post, then I'm going to leave this topic alone... Sorry for the mis-understanding about what we were talking about Wormbo, it seems once again I've managed to totally mangle the subject :(
Yeah, simulated functions check the local role, but if this actor was spawned at the other end of the pipeline first and replicated, then the local role is equal to how the remoteRole was defined in script, so that's why I mentioned it...

karminax: The simulated function tick(float dt) or weapontick of a weapon hold by the player on the listening server isn't executed on clients, even if their players see this player and his weapon. (I've checked that with log messages). Why is that? Weapons are simulated proxys, so sim.tick should be executed everywhere.

Wormbo: The weapon is only replicated to the owning client. What you see is actually the weapon's InventoryAttachment.

Matariel: I suggest that we remove this discussion, it has outlived its usefulness and it only confuses newcomers with outdated information. We should remove it as soon as we get sufficient agreement on this course of action. If anyone is against the removal of this discussion, please speak up.

Category:Legacy Refactor Me


Category:Legacy Tutorial
Category:Legacy Refactor Me
Category:Legacy To Do – This needs merged into the grand topic of Replication. See Replication/Discussing